package ddx.windows;

import java.awt.Component;
import java.util.List;

import javax.swing.JOptionPane;

import com.google.common.collect.Lists;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.BaseTSD;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinDef.LPARAM;
import com.sun.jna.platform.win32.WinDef.LRESULT;
import com.sun.jna.platform.win32.WinDef.WPARAM;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.platform.win32.WinUser.INPUT;

import ddx.DDTest.DD;
import ddx.windows.MyUser32.WindowProc;

public class WinUtil {

    private static User32 sysLib = User32.INSTANCE;
    private static MyUser32 userLib = MyUser32.INSTANCE;
    private static boolean isOk = true; // 是否正常加载主窗口句柄
    private static HWND hwnd = null; // 主窗口句柄

    /**
     * 初始化工具类
     * @param c  传入一个窗口对象(Component或它的子类)
     * @param title 传入窗口的标题(此参数和 Component 可任意一个为空)
     */
    public static void init(Component c, String title) {
        System.setProperty("jna.encoding", "utf-8");
        Pointer pointer = null;
        if(c != null){
            pointer = Native.getComponentPointer(c);
        }
        if(pointer == null){
            Logger.debug("无法找到窗口对象，正在按标题查找...");
            hwnd = sysLib.FindWindow(null, title);
        } else {
            hwnd = new HWND(pointer);
        }
        if(hwnd == null){
            Logger.debug("无法找到窗口句柄，请检查窗口标题或窗口是否存在!");
            isOk = false;
            return;
        }
        Logger.debug("找到主窗口的句柄为：" + hwnd.toString());

        /**
         * 进行窗口监听
         * 这里监听Window通知 JavaGUI绘制的一些命令
         */
        final WindowProc thisFrameEventHander = userLib.GetWindowLongPtr(hwnd, User32.GWL_WNDPROC);
        // 为自定义事件创建回调函数，并将其他消息继续转发原来的事件处理函数
        WindowProc proc = new WindowProc() {
            // 处理一个应用级别的消息（自定义消息）
            @Override
            public LRESULT callback(HWND hWnd, int uMsg, WPARAM wParam, LPARAM lParam) {
                // 可以在这里设置一些窗口消息监听之类的事情
                if (uMsg == ApiConst.WM_MOUSEACTIVATE) {
                    uMsg = ApiConst.MA_NOACTIVATE;
                }
                // Logger.debug(String.valueOf(uMsg) + " " + wParam + " " + lParam);
                // 为了不影响该Java GUI 窗口，还需要把其他消息继续转发给原有的事件处理函数。
                return thisFrameEventHander.callback(hWnd, uMsg, wParam, lParam);
            }
        };
        boolean registerWindow = (userLib.SetWindowLongPtr(hwnd, User32.GWL_WNDPROC, proc) != null ? true : false);
        int registerNOActivate = sysLib.SetWindowLong(hwnd, ApiConst.GWL_EXSTYLE,
                sysLib.GetWindowLong(hwnd, ApiConst.GWL_EXSTYLE) | ApiConst.WS_EX_NOACTIVATE);
        Logger.debug("注册窗口监听:" + registerWindow);
        Logger.debug("注册无状态栏样式:" + (registerNOActivate > 0 ? true : false));
    }

    /**
     * 按键操作
     * @param keyCode 传入的键标码
     */
    public synchronized static void keyPress(int keyCode) {
        if(!isOk) {
            JOptionPane.showMessageDialog(null, "系统初始化失败，请重新初始化");
            return;
        }
        Logger.debug("当前传入的键标码：" + keyCode);
        HWND currHwnd = userLib.GetFocus();
        attachThreadInput(currHwnd, true);
        Logger.debug("当前被选择的窗口标题：" + getCurrTitle());
        
        User32.INSTANCE.SetForegroundWindow(currHwnd);
        
        User32.INSTANCE.SetFocus(currHwnd);
        keyPressed(keyCode);
        keyRealesed(keyCode);
        attachThreadInput(currHwnd, false);
    }
    /**
     * 按键操作
     * @param keyCode 传入的键标码
     */
    public synchronized static void keyPress(int keyCode,String title) {
    	if(!isOk) {
    		JOptionPane.showMessageDialog(null, "系统初始化失败，请重新初始化");
    		return;
    	}
    	Logger.debug("当前传入的键标码：" + keyCode);
    	WinDef.HWND currHwnd = User32.INSTANCE.FindWindow(null, title);
    	
    	//HWND currHwnd = userLib.GetFocus();
    	attachThreadInput(currHwnd, true);
    	
    	Logger.debug("当前被选择的窗口标题：" + title);
    	
    	User32.INSTANCE.SetForegroundWindow(currHwnd);
    	
    	User32.INSTANCE.SetFocus(currHwnd);
    	ddKeyPressed(keyCode); 
    	attachThreadInput(currHwnd, false);
    }
    /**
     * 按键操作
     * @param keyCode 传入的键标码
     */
    public synchronized static void mousePress(String type,int keyCode,int xx,int yy,String title) {
    	 
    	Logger.debug("当前传入的键标码：" + keyCode);
    	WinDef.HWND currHwnd = User32.INSTANCE.FindWindow(null, title);
    	WinDef.RECT rect = getRect(currHwnd); 
		//System.out.println("当前坐标："+rect.top+","+rect.left+","+rect.right+","+rect.bottom);
    	//HWND currHwnd = userLib.GetFocus();
    	//attachThreadInput(currHwnd, true); 
    	Logger.debug("当前被选择的窗口标题：" + title); 
    	User32.INSTANCE.SetForegroundWindow(currHwnd); 
    	User32.INSTANCE.SetFocus(currHwnd);
    	 
    	/*if(type.equals("1")){
    		cardSelect(keyCode,rect,xx,yy);
    	}else if(type.equals("2")){
    		startGame(keyCode,rect);
    	} 
    	else{
    		cardTopSelect(keyCode,rect,xx,yy);
    	} */
    	//attachThreadInput(currHwnd,false);
    }
    
    /**
     * 按键操作
     * @param keyCode 传入的键标码
     */
    public static WinDef.RECT getForegroundWindow() { 
    	WinDef.HWND currHwnd = User32.INSTANCE.FindWindow(null, windowTitle);
    	WinDef.RECT rect = getRect(currHwnd); 
		//System.out.println("当前坐标："+rect.top+","+rect.left+","+rect.right+","+rect.bottom);
    	//HWND currHwnd = userLib.GetFocus();
    	//attachThreadInput(currHwnd, true);  
    	User32.INSTANCE.SetForegroundWindow(currHwnd); 
    	User32.INSTANCE.SetFocus(currHwnd);
    	return rect;
    }
    
    /**
     * 选择卡片
     * @param keyCode
     * @param rect
     * @param xx
     * @param yy
     */
    public static void startGame(int keyCode) {
    	WinDef.RECT rect = getForegroundWindow();
    	int x = rect.left + PvzConstant.card_select_b + PvzConstant.card_w / 2 + ( 4 *  (PvzConstant.card_w+PvzConstant.card_select_j));
    	int y = rect.top + PvzConstant.h + PvzConstant.yang_guang_h + PvzConstant.card_select_h - PvzConstant.card_select_button /2;
    	ddMousePressed(keyCode,x,y); 
    }
    /**
     * 游戏前选择植物卡片
     * @param keyCode
     * @param rect
     * @param xx
     * @param yy
     */
    public static void preCardSelect(int keyCode,int yy,int xx) {
    	WinDef.RECT rect = getForegroundWindow();
    	int x = rect.left + PvzConstant.card_select_b + PvzConstant.card_w / 2 + ( (xx-1) *  (PvzConstant.card_w+PvzConstant.card_select_j));
    	int y = rect.top + PvzConstant.h + PvzConstant.yang_guang_h + PvzConstant.card_select_top + PvzConstant.card_h /2 + ( (yy-1) * PvzConstant.card_h);
    	ddMousePressed(keyCode,x,y); 
    }
    
    /**
     * 点击最上面的卡片
     * @param keyCode
     * @param rect
     * @param xx
     * @param yy
     */
    public static void cardTopSelect(int keyCode,int xx) {
    	WinDef.RECT rect = getForegroundWindow();
    	int x = rect.left +  PvzConstant.yang_guang_w +  PvzConstant.card_w / 2 + ( (xx-1) *  (PvzConstant.card_w+PvzConstant.card_select_tj));
    	int y = rect.top +PvzConstant.h + PvzConstant.yang_guang_h /2;
    	ddMousePressed(keyCode,x,y); 
    }
    
    /**
     * 点击最上面的卡片同时放置到对应的位置
     * @param keyCode
     * @param rect
     * @param xx
     * @param yy
     */
    public static void cardTopSelectAndPut(int keyCode,int topPostion,int yy,int xx) {
    	WinDef.RECT rect = getForegroundWindow();
    	int x = rect.left +  PvzConstant.yang_guang_w +  PvzConstant.card_w / 2 + ( (topPostion-1) *  (PvzConstant.card_w+PvzConstant.card_select_tj));
    	int y = rect.top +PvzConstant.h + PvzConstant.yang_guang_h /2;
    	ddMousePressed(keyCode,x,y);  
    	x = rect.left + PvzConstant.war_out_w + PvzConstant.war_card_w / 2 + ( (xx-1) *  (PvzConstant.war_card_w));
    	y = rect.top + PvzConstant.war_out_h + PvzConstant.war_card_h /2 + ( (yy-1) * PvzConstant.war_card_h);
    	ddMousePressed(keyCode,x,y);  
    	
    }
    /**
     * 点击最上面的卡片同时放置到对应的位置
     * @param keyCode
     * @param rect
     * @param xx
     * @param yy
     */
    public static void deletePao(int keyCode,int yy,int xx) {
    	WinDef.RECT rect = getForegroundWindow();
    	int x = rect.left +  PvzConstant.yang_guang_w +  PvzConstant.card_w / 2 + ( 10 *  (PvzConstant.card_w+PvzConstant.card_select_tj));
    	int y = rect.top +PvzConstant.h + PvzConstant.yang_guang_h /2;
    	ddMousePressed(keyCode,x,y);  
    	x = rect.left + PvzConstant.war_out_w + PvzConstant.war_card_w / 2 + ( (xx-1) *  (PvzConstant.war_card_w));
    	y = rect.top + PvzConstant.war_out_h + PvzConstant.war_card_h /2 + ( (yy-1) * PvzConstant.war_card_h);
    	ddMousePressed(keyCode,x,y);  
    	
    }
    
    /**
     * 跳过游戏提示
     * @param keyCode
     * @param rect
     * @param xx
     * @param yy
     */
    public static void skipMsg() {
    	WinDef.RECT rect = getForegroundWindow(); 
    	ddKeyPressed(603);  
    }
    
    /**
     * 跳过游戏提示
     * @param keyCode
     * @param rect
     * @param xx
     * @param yy
     */
    public static void sayNo() {
    	WinDef.RECT rect = getForegroundWindow(); 
    	ddKeyPressed(100);  
    }

    /**
     * 亲和或释放线程
     * @param hwnd
     * @param isAttach
     */
    private static void attachThreadInput(HWND hwnd, boolean isAttach) {
        DWORD prepDWORD = new DWORD(User32.INSTANCE.GetWindowThreadProcessId(hwnd, null));
        DWORD currDWORD = new DWORD(Kernel32.INSTANCE.GetCurrentThreadId());
        Logger.debug((isAttach ? "亲和" : "释放") + "连接对象：" + prepDWORD.toString() + " --> " + currDWORD.toString());
        User32.INSTANCE.AttachThreadInput(prepDWORD, currDWORD, isAttach);
    }

    /**
     * 获取当前选择的窗口标题
     */
    private static String getCurrTitle(){
        HWND hwnd = sysLib.GetForegroundWindow();
        int titleSize = sysLib.GetWindowTextLength(hwnd) + 1;
        char[] windowTitle = new char[titleSize];
        sysLib.GetWindowText(hwnd, windowTitle, titleSize);
        return String.valueOf(windowTitle);
    }

    /**
     * 键按下事件
     * @param keyCode
     */
    private synchronized static void keyPressed(int keyCode) {
        INPUT ip = new INPUT();
        ip.type = new WinDef.DWORD(WinUser.INPUT.INPUT_KEYBOARD);
        ip.input.setType("ki");
        ip.input.ki.wScan = new WinDef.WORD(0);
        ip.input.ki.time = new WinDef.DWORD(Kernel32.INSTANCE.GetTickCount());
        ip.input.ki.dwExtraInfo = new BaseTSD.ULONG_PTR(0);
        ip.input.ki.wVk = new WinDef.WORD(keyCode);
        ip.input.ki.dwFlags = new WinDef.DWORD(0);
        User32.INSTANCE.SendInput(new WinDef.DWORD(1), (INPUT[]) ip.toArray(1), ip.size());
        sleep(10);
    }
    

    /**
     * 键抬起事件
     * @param keyCode
     */
    private synchronized static void keyRealesed(int keyCode) {
        INPUT ip = new INPUT();
        ip.type = new WinDef.DWORD(WinUser.INPUT.INPUT_KEYBOARD);
        ip.input.setType("ki");
        ip.input.ki.wScan = new WinDef.WORD(0);
        ip.input.ki.time = new WinDef.DWORD(Kernel32.INSTANCE.GetTickCount());
        ip.input.ki.dwExtraInfo = new BaseTSD.ULONG_PTR(0);
        ip.input.ki.wVk = new WinDef.WORD(keyCode);
        ip.input.ki.dwFlags = new WinDef.DWORD(WinUser.KEYBDINPUT.KEYEVENTF_KEYUP | 0x4);
        User32.INSTANCE.SendInput(new WinDef.DWORD(1), (INPUT[]) ip.toArray(1), ip.size());
        sleep(10);
    }
    /**
     * 键盘事件
     * @param keyCode
     */
    private synchronized static void ddKeyPressed(int keyCode) {
    	DD.INSTANCE.DD_key(keyCode,1); // 1==down 
		DD.INSTANCE.DD_key(keyCode,2); // 2=up
    	sleep(10);
    }
    /**
     * 鼠标事件
     * @param keyCode
     */
    private synchronized static void ddMousePressed(int keyCode,int x,int y) {
    	DD.INSTANCE.DD_mov(x,y);
    	sleep(100);
    	DD.INSTANCE.DD_btn(keyCode);
    	sleep(10);
    	DD.INSTANCE.DD_btn(keyCode * 2);
    	sleep(10);
    }
    
    
    /**
     * 键抬起事件
     * @param keyCode
     */
    private synchronized static void ddRealesed(int keyCode) {
    	INPUT ip = new INPUT();
    	ip.type = new WinDef.DWORD(WinUser.INPUT.INPUT_KEYBOARD);
    	ip.input.setType("ki");
    	ip.input.ki.wScan = new WinDef.WORD(0);
    	ip.input.ki.time = new WinDef.DWORD(Kernel32.INSTANCE.GetTickCount());
    	ip.input.ki.dwExtraInfo = new BaseTSD.ULONG_PTR(0);
    	ip.input.ki.wVk = new WinDef.WORD(keyCode);
    	ip.input.ki.dwFlags = new WinDef.DWORD(WinUser.KEYBDINPUT.KEYEVENTF_KEYUP | 0x4);
    	User32.INSTANCE.SendInput(new WinDef.DWORD(1), (INPUT[]) ip.toArray(1), ip.size());
    	sleep(10);
    }

    /**
     * 线程休眠
     * @param millis
     */
    private static void sleep(long millis){
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            Logger.debug(e.getMessage());
        }
    }
    private static String windowTitle = "Plants vs. Zombies";
    
    public static void main(String[] args) throws Exception {
        Logger.setOpenLog(false); // 是否打开日志
        /*JFrame frame = new JFrame("test windows");
        frame.add(new JTextField());
        frame.setSize(300, 300);
        frame.setLocation(0, 0);ab
        frame.setVisible(true);
        frame.setDefaultCloseOperation(3);*/
        //init(null, "Plants vs. Zombies"); // 初始化窗口 ab
    	DD.INSTANCE.DD_btn(0);
        //keyPress(100,"Plants vs. Zombies"); //
        //mousePress(1,"Plants vs. Zombies");//1==L.down; 2==L.up 4==R.down 8==R.up 16==M.down 32==M.up
        //keyPress(KeyEvent.VK_B);
        
        /*Scanner scanner = new Scanner(System.in);
        String line = null;
        while ((line = scanner.nextLine()) != null) {
            if ("q".equals(line)) {
                scanner.close();
                break;
            }
            line = getNbr(line);
			if(StringUtils.isNotEmpty(line)){
				String[] xy = line.split(",");
				if(xy.length>1){
					 mousePress(1,Integer.valueOf(xy[0]),Integer.valueOf(xy[1]),"Plants vs. Zombies");
				} 
			} 
            
        } */
    	 
    	/*skipMsg();
    	Thread.sleep(1000); 
    	skipMsg();
    	Thread.sleep(1000); 
    	skipMsg();
    	Thread.sleep(5000);*/
    	//测试 选择卡片
    	List<String> xys = Lists.newArrayList();
    	xys.add("5,1");   
    	xys.add("5,3");   
    	xys.add("5,4");   
    	xys.add("5,5");   
    	xys.add("5,6");   
    	xys.add("5,7");   
    	xys.add("5,8");   
    	xys.add("4,6");   
    	xys.add("4,7");  
    	for(String line : xys){
    		String[] xy = line.split(","); 
    		if(xy.length>1){
    			preCardSelect(1,Integer.valueOf(xy[0]),Integer.valueOf(xy[1]));
    		} 
    	}  
    	for(int i=0;i<7;i++){
    		cardTopSelect(1,4); 
    	} 
    	Thread.sleep(5000); 
    	startGame(1);
    	Thread.sleep(5000); 
    	sayNo();
    	Thread.sleep(5000); 
    	
    	/*cardTopSelectAndPut(1,5,1,4);
    	
    	Thread.sleep(5000); 
    	deletePao(1,1,4);*/
    	
    	
    	
    	
    	
    }
    static String getNbr(String str){ 
        // Replace each non-numeric number with a space
        str = str.replaceAll("[^\\d]", " "); 
        // Remove leading and trailing spaces
        str = str.trim(); 
        // Replace consecutive spaces with a single space
        str = str.replaceAll(" +", ","); 
  
        return str; 
    } 
    /**
     * 获取矩形
     *
     * @param hwnd
     * @return
     */
    private static WinDef.RECT getRect(WinDef.HWND hwnd) {
        WinDef.RECT winRect = new WinDef.RECT();
        sysLib.GetWindowRect(hwnd, winRect);
        return winRect;
    }

}
